﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WebUtils;

namespace OAuth
{
    class DefaultUnsignedWebRequest : IUnsignedWebRequest
    {
        public DefaultUnsignedWebRequest(
            IOAuthSessionParameter pSessionParameter,
            WebMethodVerbEnum pVerb,
            string pAddress,
            string pConsumerKey,
            string pToken,
            string pSecret,
            SignatureMethod pSignatureMethod,
            AuthInfoLocation pAuthInfoLocation,
            IEnumerable<UnEncodedURLParameter> pGetParameters,
            IEnumerable<UnEncodedURLParameter> pPostParameters,
            IEnumerable<Parameter> pHeaders)
        {
            SessionParameter = pSessionParameter;

            Verb = pVerb;
            Address = pAddress;
            GetParameters = pGetParameters != null ? pGetParameters : new UnEncodedURLParameter[] { };
            PostParameters = pPostParameters != null ? pPostParameters : new UnEncodedURLParameter[] { };
            Headers = pHeaders != null ? pHeaders : new Parameter[] { };
            SignatureMethod = pSignatureMethod;
            AuthInfoLocation = pAuthInfoLocation;
            var pair = DateTime.Now.ToUnixTimeStampAndNonce();
            Timestamp = pair.Timestamp;
            Nonce = pair.Nonce;
            Version = "1.0";

            ConsumerKey = pConsumerKey;
            Token = pToken;
            Secret = pSecret;
        }

        public ISignedWebRequest CreateSignedWebRequest()
        {
            return CreateSignedWebRequest(null);
        }

        public ISignedWebRequest CreateSignedWebRequest(IEnumerable<UnEncodedURLParameter> pExtraAuthParameters)
        {
            // gather all the parameters together
            // they are going to be used for the normalized parameter string
            // the oauth_signature parameter must obviously be added after it is calculated

            List<UnEncodedURLParameter> oauthParameters = new List<UnEncodedURLParameter>(new UnEncodedURLParameter[] {
                    new UnEncodedURLParameter() { Key = "oauth_consumer_key", Value = ConsumerKey },
                    new UnEncodedURLParameter() { Key = "oauth_signature_method", Value = SignatureMethod.Name },
                    new UnEncodedURLParameter() { Key = "oauth_timestamp", Value = Timestamp },
                    new UnEncodedURLParameter() { Key = "oauth_nonce", Value = Nonce },
                    new UnEncodedURLParameter() { Key = "oauth_version", Value = Version },
                });

            if (!string.IsNullOrEmpty(Token))
            {
                oauthParameters.Add(new UnEncodedURLParameter() { Key = "oauth_token", Value = Token });
            }

            if (pExtraAuthParameters != null)
            {
                oauthParameters.AddRange(pExtraAuthParameters);
            }

            var signature = SignatureMethod.CreateSignature(this, SessionParameter, oauthParameters);

            oauthParameters.Add(new UnEncodedURLParameter() { Key = "oauth_signature", Value = signature });

            return AuthInfoLocation.CreateSignedRequest(this, oauthParameters);
        }

        public IOAuthSessionParameter SessionParameter { get; set; }

        public string ConsumerKey { get; private set; }
        public string Token { get; private set; }
        public string Secret { get; private set; }
        
        public WebMethodVerbEnum Verb { get; private set; }
        public string Address { get; private set; }
        public IEnumerable<UnEncodedURLParameter> GetParameters { get; private set; }
        public IEnumerable<UnEncodedURLParameter> PostParameters { get; private set; }
        public IEnumerable<Parameter> Headers { get; set; }

        public string Realm { get; private set; }
        
        public SignatureMethod SignatureMethod { get; private set; }
        public AuthInfoLocation AuthInfoLocation { get; private set; }
        public string Timestamp { get; private set; }
        public string Nonce { get; private set; }
        public string Version { get; private set; }
    }

    class DefaultSignedWebRequest : ISignedWebRequest
    {
        public DefaultSignedWebRequest() { }

        public IUnsignedWebRequest UnsignedWebRequest { get; set; }
        public WebMethodVerbEnum Verb { get; set; }
        public string Address { get; set; }
        public IEnumerable<UnEncodedURLParameter> GetParameters { get; set; }
        public IEnumerable<UnEncodedURLParameter> PostParameters { get; set; }
        public IEnumerable<Parameter> Headers { get; set; }
    }

    class DefaultWebRequest : IWebRequest
    {
        readonly WebMethodVerbEnum verb;
        readonly string address;
        readonly IEnumerable<UnEncodedURLParameter> getParams;
        readonly IEnumerable<UnEncodedURLParameter> postParams;
        readonly IEnumerable<Parameter> headers;

        public DefaultWebRequest(
            WebMethodVerbEnum pVerb,
            string pAddress,
            IEnumerable<UnEncodedURLParameter> pGetParams,
            IEnumerable<UnEncodedURLParameter> pPostParams,
            IEnumerable<Parameter> pHeaders)
        {
            verb = pVerb;
            address = pAddress;
            getParams = pGetParams;
            postParams = pPostParams;
            headers = pHeaders;
        }

        public WebMethodVerbEnum Verb { get { return verb; } }
        public string Address { get { return address; } }

        public IEnumerable<UnEncodedURLParameter> GetParameters { get { return getParams; } }
        public IEnumerable<UnEncodedURLParameter> PostParameters { get { return postParams; } }
        public IEnumerable<Parameter> Headers { get { return headers; } }
    }
}
